package com.example.featuresdk.viewmodel

import android.util.Log
import android.util.LogPrinter
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.featuresdk.repository.IRepository
import com.example.featuresdk.vo.Status
import com.example.featuresdk.vo.UiState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

/**
 * View model is the business logic layer responsible for
 * 1. Use repository (data access layer) to manage changes to data model (business data layer)
 * 2. Publish changes to uiState observed by View (Compose) which will reflect the changes
 * 3. Handle events from View and perform corresponding business logic (commands), e.g. calculation, validation
 */
abstract class AbstractViewModel<T> constructor(val repository: IRepository<T>) : ViewModel() {

    protected val _uiState = MutableStateFlow(UiState<List<T>>())
    val uiState: StateFlow<UiState<List<T>>> = _uiState

    open val commands = object : UiAction<T>(){
//        override fun getAll() = launch {
//            _uiState.value = UiState(Status.Success, data = repository.getAll())
//        }

        override fun get(vararg keys: Any) = launch{
            _uiState.value = UiState(Status.Success, data = repository.get(*keys))
        }

        override fun create(item: T) = launch{
            validate(item)
            repository.create(item)
        }

        override fun delete(vararg keys: Any) = launch{
            repository.delete(keys)
        }

        override fun update(item: T) = launch{
            validate(item)
            repository.update(item)
        }
    }

    /**
     * logic to validate the item before persistence to database.
     * RuntimeException should be thrown for business rule violation
     */
    protected open fun validate(item: T) { }

    protected fun launch(uiActionCommand: suspend ()->Unit){
        viewModelScope.launch {
            try {
                uiActionCommand()
            }catch (t: Throwable){
                //_uiState.value = UiState(Status.Error, t.message)
                _uiState.value.status = Status.Error
                _uiState.value.message = t.message
                Log.e("AbstractViewModel","Error",t)
            }
        }
    }

//    init {
//        Log.e("AbstractViewModel","***init****$this")
//    }
//
//    override fun onCleared() {
//        Log.e("AbstractViewModel","***onCleared****$this")
//        super.onCleared()
//    }
}